package com.mp.approvalreq.servlet;

import com.alibaba.fastjson.JSONObject;
import com.mp.approvalreq.entity.Email;
import com.mp.approvalreq.entity.ExcelParam;
import com.mp.approvalreq.service.ReadTemplateServicePrx;
import com.mp.approvalreq.service.SubmitRequestServicePrx;
import com.mp.approvalreq.util.*;
import com.mp.user.entity.User;
import com.plusmoney.exception.RpcServerLogicalException;
import com.qq.tars.client.util.ServantUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * @author xq
 */
@WebServlet("/exportApproveExcel")
public class ExportApproveExcel extends AbstractServlet {
    private static final long serialVersionUID = -6524473373623928868L;
    private static final Logger logger = LoggerFactory.getLogger(ExportApproveExcel.class);

    private static final int CORE_POOL_SIZE = 2;
    private static final int MAXI_POOL_SIZE = 4;
    private static final int KEEP_ALIVE_TIME = 200;
    private static final LinkedBlockingQueue BLOCK_QUEUE = new LinkedBlockingQueue<Runnable>(10);
    private static final ThreadPoolExecutor THREAD_POOL = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXI_POOL_SIZE, KEEP_ALIVE_TIME, TimeUnit.MILLISECONDS, BLOCK_QUEUE);

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        doPost(req, resp);
    }

    /**
     * 前端数据: {"months":["2017-09"],"emails":["497019820@qq.com"],"templateIds":[12086],"exportType":"mySelf"}
     */
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        final String exportPath = this.getServletContext().getRealPath("/exports");
        try {
            User user = ServiceUtils.getUserInfoByRequest(req);

            String reqBody = getContent(req);
            JSONObject inputJo = JSONObject.parseObject(reqBody);
            logger.info("JSON:{}", inputJo);

            List<Integer> templateIds = CheckUtil.checkTemplateIds(inputJo);
            List<String> emails = CheckUtil.checkEmails(inputJo);
            List<String> days = CheckUtil.checkDays(inputJo);
            String exportType = CheckUtil.checkExportType(inputJo);

            ReadTemplateServicePrx readTemplateService = ServiceUtils.getReadTemplateServicePrx();

            ExcelParam excelParam = new ExcelParam(readTemplateService, days, templateIds, user.getToken(),
                    null, emails, exportPath, exportType, user);
            excelParam.setReqBody(reqBody);
            NewExportTask newTask = new NewExportTask(excelParam);
            THREAD_POOL.execute(newTask);

            try {
                if (!Objects.equals(inputJo.getInteger("isTest"), 1)) {
                    Email email = new Email();
                    email.setEmail(ListHelper.list2string(emails));
                    SubmitRequestServicePrx submitRequestServicePrx = ServantUtils.getObject(SubmitRequestServicePrx.class);
                    submitRequestServicePrx.saveExportEmail(email, user);
                }
            } catch (Exception e) {
                logger.error(e.getMessage(), e);
            }

            logThreadPoolState();
            returnResponse(resp);
        } catch (Throwable e) {
            onThrowable(req, resp, e);
        }
    }

    private void logThreadPoolState() {
        logger.info("线程池中当前线程数目:" + THREAD_POOL.getPoolSize()
                + ",队列中等待执行的任务数目:" + THREAD_POOL.getQueue().size());
        logger.info("线程池曾达到过的最大数目:" + THREAD_POOL.getLargestPoolSize()
                + ",当前活动线程数(正在工作):" + THREAD_POOL.getActiveCount());
    }

    @Override
    public void destroy() {
        THREAD_POOL.shutdown();
        super.destroy();
    }

    static class NewExportTask implements Runnable {
        ExcelParam excelParam;

        NewExportTask(ExcelParam excelParam) {
            this.excelParam = excelParam;
        }

        @Override
        public void run() {
            try {
                // 导出自己申请的,按天数
                if (excelParam.isExportMyApply() && excelParam.isExportByDay()) {
                    ExportMyApply export = new ExportMyApply(excelParam);
                    export.createExcel();

                    // 导出全公司的,按天数
                } else if (excelParam.isExportAllCompany() && excelParam.isExportByDay()) {
                    ExportAllCompanyApproval export = new ExportAllCompanyApproval(excelParam);
                    export.createExcel();

                    // 导出部分人的,按天数
                } else {
                    logger.info("user: " + excelParam.getUser().getContactId());
                    logger.info("exportType: " + excelParam.getExportType());
                    throw new RpcServerLogicalException(1, "导出类型错误");
                }

            } catch (Throwable e) {
                logger.error(e.getMessage(), e);
                User user = excelParam.getUser();
                String reqBody = excelParam.getReqBody();
                try {
                    ExcelUtil.sendQQMail("497019820@qq.com", user.getCompanyId() + "审批导出出错",
                            user.getCompanyName() + "<br>错误代码:" + e.getMessage() + "<br>" + reqBody, null);
                } catch (Throwable e2) {
                    logger.error(e2.getMessage(), e2);
                }
            }
        }
    }

    private void returnResponse(HttpServletResponse resp) throws Throwable {
        JSONObject json = new JSONObject();
        json.put("result", 0);
        json.put("res_info", "正在导出");
        resp.setHeader("Content-Type", "application/json;charset = utf-8");
        resp.setCharacterEncoding("UTF-8");
        resp.getWriter().write(json.toJSONString());
        resp.flushBuffer();
    }
}

